'''
Created on Mar 16, 2011

@author: mwarren1
'''

import sys
import os
import imaplib
import cPickle
import time
import sqlite3
import base64

import wx
from wx.tools.dbg import Logger

import MailThread
import maildroplibs

import StartupSettings

if sys.version_info < (2,7):
    from maildroplibs.OrderedDict import OrderedDict
else:
    from collections import OrderedDict

PROXY_OFF = 0
PROXY_AUTO = 1
PROXY_MAN = 2

debug = Logger('settings')
debug.SetStream(maildroplibs.DEBUGSTREAM)
debug(enable = maildroplibs.ENABLEDEBUG)

class SettingsError(Exception):
    def __init__(self, value):
        self.value = value
        self.pauseThread()
    
    def __str__(self):
        return "Settings not properly set: " + str(self.value) + "\nAll Threads have been paused"
    
    def pauseThread(self):
        MailThread.pause()
    
    def showError(self, parent = None):
        if self.value.firstrun:
            return #Don't show error on first run
        if 'wxGTK' not in wx.PlatformInfo:
            debug(str(self))
            dlg = wx.MessageDialog(parent,
                                   "It seems the settings were not properly set,\nplease open the settings and double check everything!",
                                   "Oops! It looks like you missed something!", wx.OK|wx.ICON_ERROR)
            dlg.ShowModal()
            #Upcoming in wx 2.9: ShowWindowModal()
            dlg.Destroy()
        else:
            print self
            debug(str(self))


class MailDropSettings(object):
    '''
    classdocs
    '''
    
    DEFAULT_FILENAME = "settings.mds"
    
    def __init__(self, filename = DEFAULT_FILENAME):
        '''
        Constructor
        '''
        self.firstrun = False
        
        ''' Application Settings '''
        self.CHECKINTERVAL = 5    #interval in minutes
        self.SYSTEMSTARTUP = False
        
        ''' Connection Settings '''
        self.USERNAME = None
        self.PASSWORD = None
        self.EMAILSERVER = 'imap.gmail.com'
        self.IMAPPORT = imaplib.IMAP4_PORT
        self.IMAPSSLPORT = imaplib.IMAP4_SSL_PORT
        self.SSL = True
        self.PROXY = PROXY_AUTO
        
        ''' IMAP Proxy Settings '''
        self.IMAPPROXYENABLED = False
        self.IMAPPROXYTYPE = maildroplibs.PROXY_TYPE_SOCKS4 #Default to SOCKS4
        self.IMAPPROXYURL = None
        self.IMAPPROXYPORT = 1080
        self.IMAPPROXYUSERNAME = None
        self.IMAPPROXYPASSWORD = None
        
        ''' HTTP Proxy Settings '''
        self.HTTPPROXYENABLED = False
        self.HTTPPROXYTYPE = "http"
        self.HTTPPROXYURL = None
        self.HTTPPROXYPORT = 8080
        self.HTTPPROXYUSERNAME = None
        self.HTTPPROXYPASSWORD = None
        
        ''' Download Settings '''
        #self.EMAILLABEL = 'Dropbox'
        #self.DOWNLOADFOLDER = None
        
        self.LABELDICT = OrderedDict([('Dropbox', [None, False, '']), 
                                      ('PrintMe', [os.path.join(self.getDropboxLocation(),"Print"), False, '#print is still in beta, use cautiously\n#print\n#delete'])])
        #self.OVERWRITE = False
        
        self.__tstamp = None
        self.__iptstamp = None
        self.__hptstamp = None
        
        self.filepath = os.path.join(maildroplibs.SETTINGS_DIR, filename)
        
        if os.path.exists(self.filepath):
            debug("Loading settings from file: " + self.filepath)
            try:
                with open(self.filepath, 'rb') as file:
                    savedSettings = cPickle.load(file)
            except Exception as e:
                print e
                debug(str(e))
                return
            
            keysMatch = True
            for key in self.__dict__.keys():
                if key not in savedSettings.__dict__:
                    keysMatch = False
            for key in savedSettings.__dict__.keys():
                if key not in self.__dict__:
                    keysMatch = False

            if keysMatch:
                self.__dict__ = savedSettings.__dict__
                debug(str(self))
            else:
                debug("Keys do not match! Deleting Save Settings File")
                os.remove(self.filepath)
        else:
            debug("Settings not found, loading with default")
            debug("Showing Tutorial")
            self.firstrun = True
            
        for label in self.LABELDICT.keys():
            if self.LABELDICT[label][0] is None:
                self.LABELDICT[label][0] = self.getDropboxLocation()
                
        debug(str(self.LABELDICT))
        
    def __str__(self): 
        settingsstr = "{"
        for item in self.__dict__:
            if item.count('_') == 0:
                settingsstr += '\''+item+'\': ' + str(self.__dict__[item]) +", "
        settingsstr += "}"
        return settingsstr
    
    def __getitem__(self,key): 
        if key == 'SYSTEMSTARTUP':
            self.__dict__[key] = StartupSettings.startupEnabled()
        return self.__dict__[key]
    
    def __setitem__(self, key, item): self.__dict__[key] = item
        
    def setpassword(self, pword):
        if pword is not None:
            self.__tstamp = str(time.time())
            cpw = ""
            while(len(pword) > len(self.__tstamp)):
                self.__tstamp = self.__tstamp*2
            for x in range(len(pword)):
                cpw = cpw + chr( ord(pword[x]) ^ ord(self.__tstamp[x]))
            self.PASSWORD = cpw
        else:
            self.PASSWORD = None
    
    def getpassword(self):
        if self.PASSWORD is not None:
            dpw = ""
            for x in range(len(self.PASSWORD)):
                dpw = dpw + chr( ord(self.PASSWORD[x]) ^ ord(self.__tstamp[x]))
            return dpw
        else:
            return None
    
    def setimapproxypassword(self,pword):
        if pword is not None:
            self.__iptstamp = str(time.time())
            cpw = ""
            while(len(pword) > len(self.__iptstamp)):
                self.__iptstamp = self.__iptstamp*2
            for x in range(len(pword)):
                cpw = cpw + chr( ord(pword[x]) ^ ord(self.__iptstamp[x]))
            self.IMAPPROXYPASSWORD = cpw
        else:
            self.IMAPPROXYPASSWORD = None
    
    def getimapproxypassword(self):
        if self.IMAPPROXYPASSWORD is not None:
            dpw = ""
            for x in range(len(self.IMAPPROXYPASSWORD)):
                dpw = dpw + chr( ord(self.IMAPPROXYPASSWORD[x]) ^ ord(self.__iptstamp[x]))
            return dpw
        else:
            return None
        
    def sethttpproxypassword(self,pword):
        if pword is not None:
            self.__hptstamp = str(time.time())
            cpw = ""
            while(len(pword) > len(self.__iptstamp)):
                self.__hptstamp = self.__hptstamp*2
            for x in range(len(pword)):
                cpw = cpw + chr( ord(pword[x]) ^ ord(self.__hptstamp[x]))
            self.IMAPPROXYPASSWORD = cpw
        else:
            self.IMAPPROXYPASSWORD = None
    
    def gethttpproxypassword(self):
        if self.IMAPPROXYPASSWORD is not None:
            dpw = ""
            for x in range(len(self.IMAPPROXYPASSWORD)):
                dpw = dpw + chr( ord(self.IMAPPROXYPASSWORD[x]) ^ ord(self.__hptstamp[x]))
            return dpw
        else:
            return None       
    
    def verify(self):
        '''
        Check all fields which are empty by default,
        to ensure that the values have been populated
        '''
        
        verified = (self.USERNAME is not None and \
                    self.PASSWORD is not None)
        
        if self.PROXY == maildroplibs.PROXY_MAN:
            if (self.IMAPPROXYENABLED and verified):
                verified = (self.IMAPPROXYTYPE is not None and \
                            self.IMAPPROXYURL is not None)
            
            if (self.HTTPPROXYENABLED and verified):
                verified = (self.HTTPPROXYURL is not None)
        
        if not verified: # and not self.firstrun:
            raise SettingsError(self)
        
    def save(self):
        try:
            self.verify()
        except SettingsError as e:
            print "Could not save settings: " + e.value
            debug("Could not save settings: " + e.value)
            return
        
        if not os.path.exists(maildroplibs.SETTINGS_DIR):
            os.mkdir(maildroplibs.SETTINGS_DIR)
        
        if self.filepath is None:
            self.filepath = os.path.join(maildroplibs.SETTINGS_DIR, self.__class__.DEFAULT_FILENAME)
                
        with open(self.filepath, 'wb') as file:
            cPickle.dump(self, file, 2)
        debug("Settings succesfully saved to " + self.filepath)

    def getDropboxLocation(self):
        dlfolder = ""
        #Use Desktop folder as default, for if Dropbox cannot be found
        
        defaultDir = ''
        if 'wxMSW' in wx.PlatformInfo:
            defaultDir = os.path.join(os.getenv('USERPROFILE'),"Desktop")
        else:
            defaultDir = os.path.join(os.getenv('HOME'),"Desktop")
        debug(str(defaultDir))
        if 'wxMSW' in wx.PlatformInfo:
            #In older version of DropBox, the config.db is  a SQL3 file with field dropbox_path
            # so try checking for this first
            dlfolder = defaultDir
            try:
                debug("Trying to find Dropbox directory from config.db")
                config_file = os.path.join(os.getenv("appdata"),"Dropbox","config.db")
                if os.path.exists(config_file):
                    print "line 283"
                    conn = sqlite3.connect(config_file)
                    c = conn.cursor()
                    c.execute("SELECT value FROM config WHERE key=\'dropbox_path\'")
                    fetchresult = c.fetchone()
                    if fetchresult is not None and len(fetchresult) > 0:
                        print "line 289"
                        dbpath = fetchresult[0]
                        if os.path.exists(dbpath):
                            print "line 292"
                            dlfolder = os.path.join(dbpath,"MailDrop")
                    else:
                        debug("First Dropbox Find Failed, trying host.db")
                        print "line 295"
                        config_file = os.path.join(os.getenv("appdata"),"Dropbox","host.db")
                        if os.path.exists(config_file):
                            with open(config_file, 'r') as file:
                                for line in file:
                                    b64line = base64.b64decode(line)
                                    print b64line
                                    if os.path.exists(b64line):
                                        print "Dropbox folder is " + b64line
                                        dlfolder = os.path.join(b64line,"MailDrop")
            except:
                debug("Both Dropbox Find Failed, using default dir")
                dlfolder = defaultDir
            #else:
            #    print "line 310"
            #    dlfolder = defaultDir
        if 'wxGTK' in wx.PlatformInfo:
            dlfolder = defaultDir
            try:
                debug("Trying to find Dropbox directory from config.db")
                config_file = os.path.join(os.getenv("HOME"),".dropbox","config.db")
                if os.path.exists(config_file):
                    conn = sqlite3.connect(config_file)
                    c = conn.cursor()
                    c.execute("SELECT value FROM config WHERE key=\'dropbox_path\'")
                    dbpath = c.fetchone()[0]
                    if os.path.exists(dbpath):
                        dlfolder = os.path.join(dbpath,"MailDrop")
                    else:
                        dlfolder = defaultDir
                else:
                    debug("First Dropbox Find Failed, trying host.db")
                    print "line 295"
                    config_file = os.path.join(os.getenv("appdata"),"Dropbox","host.db")
                    if os.path.exists(config_file):
                        with open(config_file, 'r') as file:
                            for line in file:
                                b64line = base64.b64decode(line)
                                print b64line
                                if os.path.exists(b64line):
                                    print "Dropbox folder is " + b64line
                                    dlfolder = os.path.join(b64line,"MailDrop")
            except:
                debug("Both Dropbox Finds Failed, using default dir")
                dlfolder = defaultDir
        if 'wxMac' in wx.PlatformInfo:
            dlfolder = defaultDir
            try:
                debug("Trying to find Dropbox directory from config.db")
                config_file = os.path.join(os.getenv("HOME"),".dropbox","config.db")
                if os.path.exists(config_file):
                    conn = sqlite3.connect(config_file)
                    c = conn.cursor()
                    c.execute("SELECT value FROM config WHERE key=\'dropbox_path\'")
                    dbpath = c.fetchone()[0]
                    if os.path.exists(dbpath):
                        dlfolder = os.path.join(dbpath,"MailDrop")
                    else:
                        dlfolder = defaultDir
                else:
                    debug("First Dropbox Find Failed, trying host.db")
                    print "line 295"
                    config_file = os.path.join(os.getenv("appdata"),"Dropbox","host.db")
                    if os.path.exists(config_file):
                        with open(config_file, 'r') as file:
                            for line in file:
                                b64line = base64.b64decode(line)
                                print b64line
                                if os.path.exists(b64line):
                                    print "Dropbox folder is " + b64line
                                    dlfolder = os.path.join(b64line,"MailDrop")
            except:
                dlfolder = defaultDir
        return dlfolder